﻿using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Furion.RemoteRequest.Extensions;
using iWare.Wms.Application.DING;
using iWare.Wms.Core;
using Magicodes.ExporterAndImporter.Excel;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Serilog;
using System.Linq.Dynamic.Core;

namespace iWare.Wms.Application
{
    /// <summary>
    /// 收货列表服务
    /// </summary>
    [Route("api/CollectList")]
    [ApiDescriptionSettings("收货列表", Name = "CollectList", Order = 110)]

    public class CollectListService : ControllerBase, IDynamicApiController, ITransient
    {
        private readonly IMemoryCache _memoryCache;
        private readonly IRepository<WareDictData, MasterDbContextLocator> _wareDictDataRep; //仓库字典值仓储
        private readonly IRepository<GoodsDelivery, MasterDbContextLocator> _goodsDeliveryRep; //送货单仓储
        private readonly IRepository<GoodsDeliveryDetails, MasterDbContextLocator> _goodsDeliveryDetailsRep; //送货单明细仓储
        private readonly IRepository<PurchaseOrderVsGoodsDelivery, MasterDbContextLocator> _purchaseOrderVsGoodsDeliveryRep; //采购订单与送货单关系仓储
        private readonly IRepository<CollectDelivery, MasterDbContextLocator> _collectDeliveryRep; //收货单仓储
        private readonly IRepository<CollectDeliveryDetails, MasterDbContextLocator> _collectDeliveryDetailsRep; //收货单明细仓储
        private readonly IRepository<GoodsDeliveryVsCollectDelivery, MasterDbContextLocator> _goodsDeliveryVsCollectDeliveryRep; //送货单与收货单关系仓储
        private readonly IRepository<QualityFeedbackDetails, MasterDbContextLocator> _qualityFeedbackDetailsRep; //质检反馈明细仓储

        #region 默认
        /// <summary>
        /// 默认
        /// </summary>
        /// <param name="memoryCache"></param>
        /// <param name="wareDictDataRep"></param>
        /// <param name="goodsDeliveryRep"></param>
        /// <param name="goodsDeliveryDetailsRep"></param>
        /// <param name="purchaseOrderVsGoodsDeliveryRep"></param>
        /// <param name="collectDeliveryRep"></param>
        /// <param name="collectDeliveryDetailsRep"></param>
        /// <param name="goodsDeliveryVsCollectDeliveryRep"></param>
        /// <param name="qualityFeedbackDetailsRep"></param>
        public CollectListService(
            IMemoryCache memoryCache,
            IRepository<WareDictData, MasterDbContextLocator> wareDictDataRep,
            IRepository<GoodsDelivery, MasterDbContextLocator> goodsDeliveryRep,
            IRepository<GoodsDeliveryDetails, MasterDbContextLocator> goodsDeliveryDetailsRep,
            IRepository<PurchaseOrderVsGoodsDelivery, MasterDbContextLocator> purchaseOrderVsGoodsDeliveryRep,
            IRepository<CollectDelivery, MasterDbContextLocator> collectDeliveryRep,
            IRepository<CollectDeliveryDetails, MasterDbContextLocator> collectDeliveryDetailsRep,
            IRepository<GoodsDeliveryVsCollectDelivery, MasterDbContextLocator> goodsDeliveryVsCollectDeliveryRep,
            IRepository<QualityFeedbackDetails, MasterDbContextLocator> qualityFeedbackDetailsRep

            )
        {
            _memoryCache = memoryCache;
            _wareDictDataRep = wareDictDataRep;
            _goodsDeliveryRep = goodsDeliveryRep;
            _goodsDeliveryDetailsRep = goodsDeliveryDetailsRep;
            _purchaseOrderVsGoodsDeliveryRep = purchaseOrderVsGoodsDeliveryRep;
            _collectDeliveryRep = collectDeliveryRep;
            _collectDeliveryDetailsRep = collectDeliveryDetailsRep;
            _goodsDeliveryVsCollectDeliveryRep = goodsDeliveryVsCollectDeliveryRep;
            _qualityFeedbackDetailsRep = qualityFeedbackDetailsRep;
        }
        #endregion

        /// <summary>
        /// 分页查询收货列表
        /// </summary>
        /// <returns></returns>
        [HttpGet("Page")]
        public async Task<PageResult<CollectListOutput>> Page([FromQuery] CollectListInput input)
        {
            var list = await _collectDeliveryDetailsRep.DetachedEntities
                .Where(input.IsQuality != YesOrNot.All, p => p.IsQuality == input.IsQuality)
                .Where(input.QualityResult != QualityEnum.All, p => p.QualityResult == input.QualityResult)
                .Where(!string.IsNullOrEmpty(input.DeliveryNo), u => EF.Functions.Like(u.CollectDelivery.DeliveryNo, $"%{input.DeliveryNo.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.ProjectCode), u => EF.Functions.Like(u.ProjectCode, $"%{input.ProjectCode.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.Code), u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.CreatedUserName), u => EF.Functions.Like(u.CreatedUserName, $"%{input.CreatedUserName.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.SearchBeginTime), u => u.CreatedTime >= DateTime.Parse(input.SearchBeginTime.Trim()) &&
                 u.CreatedTime <= DateTime.Parse(input.SearchEndTime.Trim()))
                .OrderBy(PageInputOrder.OrderBuilder(input))
                .ProjectToType<CollectListOutput>()
                .ToADPagedListAsync(input.PageNo, input.PageSize);

            foreach (var item in list.Rows)
            {
                var purchaseOrderVsGoodsDelivery = await _purchaseOrderVsGoodsDeliveryRep.DetachedEntities
                    .Where(z => z.GoodsDelivery.DeliveryNo == item.CollectDelivery.DeliveryNo)
                    .ProjectToType<PurchaseOrderVsGoodsDelivery>().FirstOrDefaultAsync();
                item.PurchaseNo = purchaseOrderVsGoodsDelivery == null ? "" : purchaseOrderVsGoodsDelivery.PurchaseOrder.IsJiaJiJian == YesOrNot.Y ? "" : purchaseOrderVsGoodsDelivery.PurchaseOrder.PurchaseNo;
                item.MaterialTagCode = ("{\"Code\":\"" + item.Code + "\"}");
            }

            return list;
        }

        /// <summary>
        /// 根据条件查询所有收货列表
        /// </summary>
        /// <returns></returns>
        [HttpGet("CollectList")]
        public async Task<List<CollectListOutput>> CollectList([FromQuery] CollectListInput input)
        {
            var list = await _collectDeliveryDetailsRep.DetachedEntities
                .Where(input.IsQuality != YesOrNot.All, p => p.IsQuality == input.IsQuality)
                .Where(input.QualityResult != QualityEnum.All, p => p.QualityResult == input.QualityResult)
                .Where(!string.IsNullOrEmpty(input.DeliveryNo), u => EF.Functions.Like(u.CollectDelivery.DeliveryNo, $"%{input.DeliveryNo.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.ProjectCode), u => EF.Functions.Like(u.ProjectCode, $"%{input.ProjectCode.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.Code), u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.CreatedUserName), u => EF.Functions.Like(u.CreatedUserName, $"%{input.CreatedUserName.Trim()}%"))
                .Where(!string.IsNullOrEmpty(input.SearchBeginTime), u => u.CreatedTime >= DateTime.Parse(input.SearchBeginTime.Trim()) &&
                 u.CreatedTime <= DateTime.Parse(input.SearchEndTime.Trim()))
                .OrderBy(PageInputOrder.OrderBuilder(input))
                .ProjectToType<CollectListOutput>()
                .ToListAsync();

            foreach (var item in list)
            {
                var purchaseOrderVsGoodsDelivery = await _purchaseOrderVsGoodsDeliveryRep.DetachedEntities
                    .Where(z => z.GoodsDelivery.DeliveryNo == item.CollectDelivery.DeliveryNo)
                    .ProjectToType<PurchaseOrderVsGoodsDelivery>().FirstOrDefaultAsync();
                item.PurchaseNo = purchaseOrderVsGoodsDelivery == null ? "" : purchaseOrderVsGoodsDelivery.PurchaseOrder.IsJiaJiJian == YesOrNot.Y ? "" : purchaseOrderVsGoodsDelivery.PurchaseOrder.PurchaseNo;
                item.MaterialTagCode = ("{\"Code\":\"" + item.Code + "\"}");
            }

            return list;
        }

        /// <summary>
        /// 导出查询收货列表
        /// </summary>
        /// <returns></returns>
        [HttpGet("Export")]
        public async Task<IActionResult> Export([FromQuery] CollectListInput input)
        {
            var collectDeliveryDetails = await _collectDeliveryDetailsRep.DetachedEntities
             .Where(input.IsQuality != YesOrNot.All, p => p.IsQuality == input.IsQuality)
             .Where(input.QualityResult != QualityEnum.All, p => p.QualityResult == input.QualityResult)
             .Where(!string.IsNullOrEmpty(input.DeliveryNo), u => EF.Functions.Like(u.CollectDelivery.DeliveryNo, $"%{input.DeliveryNo.Trim()}%"))
             .Where(!string.IsNullOrEmpty(input.ProjectCode), u => EF.Functions.Like(u.ProjectCode, $"%{input.ProjectCode.Trim()}%"))
             .Where(!string.IsNullOrEmpty(input.Code), u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%"))
             .Where(!string.IsNullOrEmpty(input.CreatedUserName), u => EF.Functions.Like(u.CreatedUserName, $"%{input.CreatedUserName.Trim()}%"))
             .Where(!string.IsNullOrEmpty(input.SearchBeginTime), u => u.CreatedTime >= DateTime.Parse(input.SearchBeginTime.Trim()) &&
              u.CreatedTime <= DateTime.Parse(input.SearchEndTime.Trim()))
             .OrderBy(PageInputOrder.OrderBuilder(input))
             .ProjectToType<ExportCollectListOutput>()
             .ToListAsync();

            foreach (var item in collectDeliveryDetails)
            {
                // 查询收货主表信息
                var collectDelivery = await _collectDeliveryRep.FirstOrDefaultAsync(z => z.Id == item.CollectDeliveryId);

                // 送货单号
                item.DeliveryNo = collectDelivery != null ? collectDelivery.DeliveryNo : "";

                // 合格数
                if (item.InspectionMethod == InspectionMethodEnum.mianjian)
                    item.HeGeQuality = item.CollectQuantity;
                else if (item.InspectionMethod != InspectionMethodEnum.mianjian && item.IsQuality == YesOrNot.Y)
                    item.HeGeQuality = new decimal(0.00);
                else item.HeGeQuality = item.CollectQuantity - item.QualityNumber;

                // 检验方式
                if (item.InspectionMethod == InspectionMethodEnum.mianjian)
                    item.InspectionMethodName = "免检";
                else if (item.InspectionMethod == InspectionMethodEnum.choujian_jianliang)
                    item.InspectionMethodName = "抽检(减量)";
                else if (item.InspectionMethod == InspectionMethodEnum.choujian_zhengchang)
                    item.InspectionMethodName = "抽检(正常)";
                else if (item.InspectionMethod == InspectionMethodEnum.choujian_jiayan)
                    item.InspectionMethodName = "抽检(加严)";
                else item.InspectionMethodName = "全检";

                // 质检结果
                if (item.IsQuality == YesOrNot.N) item.QualityResultName = "N/A";
                else if (item.QualityResult == QualityEnum.HeGe)
                    item.QualityResultName = "合格";
                else if (item.QualityResult == QualityEnum.FanXiu)
                    item.QualityResultName = "返修";
                else if (item.QualityResult == QualityEnum.BaoFei)
                    item.QualityResultName = "报废";
                else if (item.QualityResult == QualityEnum.JiShu)
                    item.QualityResultName = "技术确认";
                else if (item.QualityResult == QualityEnum.RangBu)
                    item.QualityResultName = "让步接收";
                else if (item.QualityResult == QualityEnum.TuiHuo)
                    item.QualityResultName = "退货";
                else item.QualityResultName = "免检";
            }

            var exporter = new ExcelExporter();
            var result = await exporter.ExportAsByteArray(collectDeliveryDetails);
            var memoryStream = new MemoryStream(result);
            return await Task.FromResult(new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
            {
                FileDownloadName = $"{DateTimeOffset.Now:yyyyMMdd_HHmmss}_收货列表.xlsx"
            });

            //string fileName = "收货列表" + DateTime.Now.ToString("yyyyMMddHHmmss");
            //var excelBaseResult = new Excel2003Result<ExportCollectListOutput>(list, fileName, false, "收货列表");
            //return File(excelBaseResult.GetExcelStream(), "application/vnd.ms-excel");
        }

        /// <summary>
        /// 分页查询送货质检明细
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("DeliveryQualityDetailsPage")]
        public async Task<PageResult<GoodsDeliveryOutput>> DeliveryQualityDetailsPage([FromQuery] CollectQualityDetailsInput input)
        {
            var list = await _goodsDeliveryRep.DetachedEntities
                .Where(!string.IsNullOrEmpty(input.DeliveryNo), expression: u => EF.Functions.Like(u.DeliveryNo, $"%{input.DeliveryNo.Trim()}%"))
                .OrderBy(PageInputOrder.OrderBuilder(input))
                .ProjectToType<GoodsDeliveryOutput>()
                .ToADPagedListAsync(input.PageNo, input.PageSize);

            foreach (var item in list.Rows)
            {
                item.DeliveryType = (await _wareDictDataRep.FirstOrDefaultAsync(z => z.Code == item.DeliveryType)).Value;
            }

            return list;
        }

        /// <summary>
        /// 更新质检结果
        /// </summary>
        /// <returns></returns>
        [HttpPost("EditIsQualified")]
        [UnitOfWork]
        public async Task EditIsQualified([FromBody] UpdateIsQualityInput input)
        {
            var model = await _collectDeliveryDetailsRep.DetachedEntities.Where(z => z.Id == input.Id)
                .ProjectToType<CollectDeliveryDetails>().FirstOrDefaultAsync();
            if (model == null) throw Oops.Oh("数据不存在!");

            // 更新质检结果和质检结果数量
            model.IsQuality = YesOrNot.Y;
            model.QualityResult = input.QualityResult;
            model.QualityNumber = input.QualityNumber;
            await _collectDeliveryDetailsRep.UpdateAsync(model);

            // 新增质检反馈明细
            var qualityModel = new QualityFeedbackDetails()
            {
                DeliveryNo = model.CollectDelivery.DeliveryNo,
                SupperCode = model.CollectDelivery.SupplierInfoCode,
                ProjectCode = model.ProjectCode,
                Code = model.Code,
                Name = model.Name,
                SpecificationModel = model.SpecificationModel,
                QualityResult = input.QualityResult,
                QualityNumber = input.QualityNumber,
                CreatedTime = DateTimeOffset.Now
            };

            await _qualityFeedbackDetailsRep.InsertAsync(qualityModel);
        }

        /// <summary>
        /// 批量质检
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("BatchEditQualified")]
        public async Task BatchEditQualified([FromBody] BatchCollectDeliveryNoInput input)
        {
            int length = input.DeliveryNo.Count;
            for (int i = 0; i < length; i++)
            {
                string deliveryNo = input.DeliveryNo[i];

                var collectDeliveryNoInput = new CollectDeliveryNoInput
                {
                    DeliveryNo = deliveryNo
                };
                await ReturnDeliveryNo(collectDeliveryNoInput);
            }
        }

        /// <summary>
        /// 删除收货数据
        /// </summary>
        /// <returns></returns>
        [HttpPost("DeleteCollect")]
        [UnitOfWork]
        public async Task DeleteCollect([FromBody] DeleteModel input)
        {
            var model = await _collectDeliveryDetailsRep.FirstOrDefaultAsync(z => z.Id == input.Id);
            if (model == null) throw Oops.Oh("数据不存在!");
            if (model.IsQuality == YesOrNot.Y) throw Oops.Oh("物料已质检请联系管理员!");

            //更新收货主表
            var collectDelivery = await _collectDeliveryRep.FirstOrDefaultAsync(p => p.Id == model.CollectDeliveryId);
            if (collectDelivery != null)
            {
                collectDelivery.CollectQuantityTotal -= model.CollectQuantity;
                await _collectDeliveryRep.UpdateAsync(collectDelivery);
            }

            //更新送货单明细表
            var goodsDelivery = await _goodsDeliveryDetailsRep.FirstOrDefaultAsync(n => n.GoodsDelivery.DeliveryNo == collectDelivery.DeliveryNo
            && n.ProjectCode == model.ProjectCode && n.Code == model.Code);
            if (goodsDelivery != null)
            {
                goodsDelivery.CollectQuantity -= model.CollectQuantity;
                await _goodsDeliveryDetailsRep.UpdateAsync(goodsDelivery);
            }

            //删除明细表
            await _collectDeliveryDetailsRep.DeleteAsync(model);
        }

        /// <summary>
        /// 获取质检后的送货单号
        /// </summary>
        /// <returns></returns>
        [HttpGet("ReturnDeliveryNo")]
        [AllowAnonymous]
        [UnitOfWork]
        public async Task ReturnDeliveryNo([FromQuery] CollectDeliveryNoInput input)
        {
            // 写日志文件
            Log.Error("ReturnDeliveryNo:" + input.DeliveryNo);

            //质检操作
            var response = await "https://api.dingtalk.com/v1.0/yida/forms/instances/search"
                                        .SetHttpMethod(System.Net.Http.HttpMethod.Post)
                                        .SetHeaders(new Dictionary<string, object> {
                                                { "x-acs-dingtalk-access-token", GetAccessToken()},
                                        })
                                        .SetBody(new Dictionary<string, object> {
                                                { "systemToken", "3L966J7194R41Z80E6B0C8QW0A9R3R8FRBM9LU21" },
                                                { "searchFieldJson", "{\"textField_l9qmo4sl\": "+input.DeliveryNo+"}" },
                                                { "formUuid", "FORM-RK966E71SAC7FWE5D94KY67A88HB2Y5DGY0DLQ"},//"FORM-K5A66M71JVY4JOKRAC1UY9JFCMG43CMQNMQ9LK" 
                                                { "userId", "01234516621139759" },
                                                { "appType", "APP_H63D59RTBUA54YVG8WQN" }
                                        }, "application/json")
                                        .PostAsAsync<RootResult>();

            if (response.totalCount > 0)
            {
                if (response.data.Count() > 0)
                {
                    var data = response.data[0];
                    if (data != null)
                    {
                        foreach (var item in data.formData.tableField_l9qmo4sn)
                        {
                            var collectDeliveryDetailModel = await _collectDeliveryDetailsRep.FirstOrDefaultAsync(n =>
                            n.CollectDelivery.DeliveryNo == input.DeliveryNo && n.Code == item.textField_laki7n3o);
                            if (collectDeliveryDetailModel != null)
                            {
                                collectDeliveryDetailModel.IsQuality = YesOrNot.Y;
                                collectDeliveryDetailModel.QualityResult = GetQualityResult(item.selectField_l9qmo4su);
                                collectDeliveryDetailModel.QualityNumber = item.numberField_l9qmo4sy;
                                await _collectDeliveryDetailsRep.UpdateAsync(collectDeliveryDetailModel);
                            }

                            var qualityFeedbackDetails = await _qualityFeedbackDetailsRep.FirstOrDefaultAsync(n => n.DeliveryNo == input.DeliveryNo
                            && n.Code == item.textField_laki7n3o);
                            if (qualityFeedbackDetails != null)
                            {
                                qualityFeedbackDetails.QualityResult = GetQualityResult(item.selectField_l9qmo4su);
                                qualityFeedbackDetails.IsAdminRead = YesOrNot.N;
                                qualityFeedbackDetails.IsSupperRead = YesOrNot.N;
                                qualityFeedbackDetails.QualityNumber = item.numberField_l9qmo4sy;
                                await _qualityFeedbackDetailsRep.UpdateAsync(qualityFeedbackDetails);
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 获取AccessToken
        /// </summary>
        /// <returns></returns>
        [HttpGet("GetAccessToken")]
        [NonUnify]
        [AllowAnonymous]
        [NonAction]
        public string GetAccessToken()
        {
            var token = _memoryCache.Get(CommonConst.DD_ACCESSTOKEN_CODE);
            if (token != null) return token.ToString();

            var response = "https://oapi.dingtalk.com/gettoken?appkey={appkey}&appsecret={appsecret}".
                                  SetTemplates(new Dictionary<string, object> {
                                                { "appkey", "dingdktlsxvypzpyqyyw" },
                                                { "appsecret", "BDPhaENcU9Y37zse-jxkpSJUDwWKLvLbrcAINLnJBrsoSfeNZg8bv-HAW1DJvqsY" }})
                                  .GetAsAsync<DingDingAccessToken>();

            if (response.Result.errcode == 0)
            {
                var cacheOptions = new MemoryCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromSeconds(7200));
                _memoryCache.Set(CommonConst.DD_ACCESSTOKEN_CODE, response.Result.access_token, cacheOptions);
                return response.Result.access_token;
            }

            return response.Result.errmsg;
        }

        /// <summary>
        /// 获取质检结果
        /// </summary>
        /// <param name="QualityResult"></param>
        /// <returns></returns>
        [NonAction]
        public QualityEnum GetQualityResult(string QualityResult)
        {
            switch (QualityResult)
            {
                case "合格":
                    return QualityEnum.HeGe;
                case "返修":
                    return QualityEnum.FanXiu;
                case "报废":
                    return QualityEnum.BaoFei;
                case "技术确认":
                    return QualityEnum.JiShu;
                case "让步接收":
                    return QualityEnum.RangBu;
                case "退货":
                    return QualityEnum.TuiHuo;
                case "免检":
                    return QualityEnum.MianJian;
                default:
                    return QualityEnum.MianJian;
            }
        }
    }
}
